package com.yuanzhy.tools.commons.math.ml;

import org.apache.commons.math3.ml.distance.CanberraDistance;
import org.apache.commons.math3.ml.distance.ChebyshevDistance;
import org.apache.commons.math3.ml.distance.DistanceMeasure;
import org.apache.commons.math3.ml.distance.EuclideanDistance;
import org.apache.commons.math3.ml.distance.ManhattanDistance;
import org.junit.Test;

import static com.yuanzhy.tools.commons.Util.println;

/**
 * 各种距离计算
 * https://blog.csdn.net/m0_37919619/article/details/118370304
 */
public class DistanceDemo {
    // x, y 坐标
    private double[] d1 = {3, 4};
    private double[] d2 = {1, 1};
    /**
     * 欧几里得距离（欧式距离）
     * c = sqrt{(x1-x2)^2 + (y1-y2)^2}
     */
    @Test
    public void euclidean() {
        DistanceMeasure dis = new EuclideanDistance();
        double d = dis.compute(d1, d2);
        println(d); // 3.605551275463989
    }

    /**
     * 曼哈顿距离
     * 在国际象棋棋盘（图 2）上，有这种横平竖直的格子，描述格子和格子之间的距离可以直接用曼哈顿距离。
     * 曼哈顿距离又被称为出租车距离是因为在像纽约曼哈顿区这样的地区有很多由横平竖直的街道所切成的街区（Block），出租车司机计算从一个位置到另一个位置的距离，通常直接用街区的两个坐标分别相减，再相加，这个结果就是他即将开车通过的街区数量
     * c = |x1-x2| + |y1-y2|
     */
    @Test
    public void manhattan() {
        DistanceMeasure dis = new ManhattanDistance();
        double d = dis.compute(d1, d2);
        println(d); // 5.0
    }

    /**
     * 堪培拉距离
     * 堪培拉距离是曼哈顿距离的加权版本
     * c(x,y) = ∑(i=1~n){ |xi-yi| / |xi|+|qi| }
     */
    @Test
    public void canberra() {
        DistanceMeasure dis = new CanberraDistance();
        double d = dis.compute(d1, d2);
        println(d); // 1.1
    }

    /**
     * 切比雪夫距离
     * 在数学中，切比雪夫距离（Chebyshev distance）或是L∞度量，√是向量空间中的一种度量，二个点之间的距离定义是其各坐标数值差绝对值的最大值。以数学的观点来看，切比雪夫距离是由一致范数（uniform norm）（或称为上确界范数）所衍生的度量，也是超凸度量（injective metric space）的一种。
     * 国际象棋棋盘上二个位置间的切比雪夫距离是指王要从一个位子移至另一个位子需要走的步数。由于王可以往斜前或斜后方向移动一格，因此可以较有效率的到达目的的格子。图1是棋盘上所有位置距f6位置的切比雪夫距离。一维空间中，所有的Lp度量都是一样的－即为二座标差的绝对值。
     */
    @Test
    public void chebyshev() {
        DistanceMeasure dis = new ChebyshevDistance();
        double d = dis.compute(d1, d2);
        println(d); // 3.0
    }

    /**
     * 推土机距离
     * Wasserstein距离也叫做推土机距离（Earth Mover's distance），这也是由于它的推导过程可以很形象的用挖土填土来解释，这也是因为该距离定义中由一个分布转变为另一个分布所需要的代价和挖土填土的过程十分相似。考虑两个离散的分布P和Q
     */
    @Test
    public void earthMovers() {
        // TODO
//        DistanceMeasure dis = new EarthMoversDistance();
//        double d = dis.compute(d1, d2);
//        println(d);
    }
}
